/*
 * Copyright (c) GoKeep by gokeep.org. 2022-2023. All rights reserved
 */
package org.gokeep.communication.engine;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.gokeep.common.config.properties.HeartProperties;
import org.gokeep.communication.message.MessageBuilder;
import org.gokeep.communication.proto.CommandProto;
import org.gokeep.communication.proto.MessageProto;
import org.smartboot.socket.extension.plugins.HeartPlugin;
import org.smartboot.socket.transport.AioSession;
import org.smartboot.socket.transport.WriteBuffer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
public class HeartPluginConfig {

    @Resource
    private HeartProperties heartProperties;

    @Bean
    public HeartPlugin<MessageProto.Message> heartPlugin() {
        return new HeartPlugin<>(heartProperties.getRate(), heartProperties.getTimeout(), TimeUnit.SECONDS) {
            @Override
            public void sendHeartRequest(AioSession session) throws IOException {
                WriteBuffer writeBuffer = session.writeBuffer();
                MessageProto.Message message = MessageBuilder.builder().initMessage(CommandProto.CommandEnum.HEART);
                byte[] bytes = message.toByteArray();
                writeBuffer.writeInt(bytes.length);
                writeBuffer.write(bytes);
                writeBuffer.flush();
                log.info("Heart: [server -> client], sessionId: [{}], SerializeNo: [{}], Address: [{}]", session.getSessionID(), message.getSerializeNo(), session.getRemoteAddress());
            }

            @Override
            public boolean isHeartMessage(AioSession session, MessageProto.Message msg) {
                if (CommandProto.CommandEnum.HEART_ACK.equals(msg.getCommand())) {
                    log.info("Heart: [client (ack)-> server], sessionId[{}], SerializeNo: [{}]",session.getSessionID(), msg.getSerializeNo());
                    return true;
                }
                return false;
            }
        };
    }
}